import { defineStore, acceptHMRUpdate } from "pinia";
import { computed, onMounted, onUnmounted, ref, watch } from "vue";
import { type UnlistenFn, listen } from "@tauri-apps/api/event";
import { Playlist, PlaylistObjectKey, PlayMode, PlayState } from "@/lib/playlist";
import { Midi, type MidiItem } from "@/lib/midi";
import useMapperStore from "./mapper";

const usePlaylistStore = defineStore("playlist", () => {
    const mapper = useMapperStore();

    const playlist = ref(Playlist.object());
    const duration = ref(0);

    let durationInterval: NodeJS.Timer | null;
    let unlistens: UnlistenFn[] = [];

    // 随时修改 mapper
    watch(
        () => mapper.now,
        (mapper) => {
            playlist.value.mapper = mapper;
            Playlist.Player.close(playlist.value);
        },
    );

    // 初始化操作
    onMounted(() => {
        // 加载播放列表
        load();

        // 不断更新 duration
        durationInterval = setInterval(() => {
            if (playlist.value.player.id === "") {
                duration.value = 0;
            } else if (playlist.value.player.state === PlayState.Play) {
                duration.value = new Date().getTime() - playlist.value.player.start.getTime();
            } else {
                duration.value = playlist.value.player.point;
            }
        }, 100);

        // 监听播放结束事件
        listen<{
            id: string;
            isPause: boolean;
        }>("midi-play-finish", async (event) => {
            let payload = event.payload;
            const player = playlist.value.player;

            if (player.id === "") {
                return;
            }

            if (payload.id === player.id && player.state === PlayState.Play) {
                // 状态更改为停止
                player.state = PlayState.Stop;

                // 关闭当前播放 Midi
                await Playlist.Player.close(playlist.value);

                // 正常播放结束，按照模式播放下一首或停止播放
                if (!payload.isPause) {
                    const newFocus = Playlist.nextFocus(playlist.value);
                    await setFocus(newFocus);
                    await Playlist.Player.play(playlist.value);
                }
            }
        }).then((value) => {
            unlistens.push(value);
        });

        // 监听文件拖拽事件
        listen<string[]>("tauri://file-drop", async (event) => {
            // 把拖拽的文件加入到播放列表
            const tasks = event.payload.map((path) => Midi.fromUrl(path));
            const items = (await Promise.all(tasks)).filter((item) => item !== undefined) as MidiItem[];
            if (items.length === 0) {
                return;
            }
            await insert(...items);
        }).then((value) => {
            unlistens.push(value);
        });
    });

    // 析构操作
    onUnmounted(() => {
        // 清除 duration 更新定时器
        if (durationInterval !== null) {
            clearInterval(Number(durationInterval));
        }

        // 取消监听
        for (let unlisten of unlistens) {
            unlisten();
        }
        unlistens.length = 0;
    });

    /**
     * 加载 Playlist
     * @param loadKeys 加载的键
     */
    async function load(...loadKeys: PlaylistObjectKey[]) {
        // 保证关闭
        if (Playlist.Player.isPlaying(playlist.value)) {
            Playlist.Player.close(playlist.value);
        }

        // 加载数据
        playlist.value = await Playlist.load(...loadKeys);

        // 初始化 mapper
        playlist.value.mapper = mapper.now;
    }

    /**
     * 保存 Playlist
     * @param saveKeys 保存的键
     */
    async function save(...saveKeys: PlaylistObjectKey[]) {
        await Playlist.save(playlist.value, ...saveKeys);
    }

    /**
     * 获取焦点
     * @returns 当前焦点的索引
     */
    function getFocus(): number {
        return playlist.value.focus;
    }

    /**
     * 设置焦点
     * @param index 焦点位置的索引
     */
    async function setFocus(index: number) {
        if (getFocus() === index) {
            return;
        }
        playlist.value.focus = index;
        await Promise.all([save("focus"), Playlist.Player.close(playlist.value)]);
    }

    /**
     * 获取播放模式
     * @returns 播放模式
     */
    function getMode(): PlayMode {
        return playlist.value.mode;
    }

    /**
     * 设置播放模式
     * @param mode 播放模式
     */
    async function setMode(mode: PlayMode) {
        if (getMode() === mode) {
            return;
        }
        playlist.value.mode = mode;
        await save("mode");
    }

    /**
     * 向播放列表中插入指定名称的 Midi 项
     * @param items 要插入的 Midi 项（可以指定索引，不指定默认为最后）
     */
    async function insert(...items: (MidiItem | [MidiItem, number])[]) {
        // 调用 Playlist.insert 方法插入指定 Midi 项
        for (let arg of items) {
            if (Array.isArray(arg)) {
                Playlist.insert(playlist.value, arg[0], arg[1]);
            } else {
                Playlist.insert(playlist.value, arg);
            }
        }

        // 进行保存
        await save("focus", "indexes", "items");
    }

    /**
     * 删除指定索引的 Midi 项
     * @param indexes 要删除的 Midi 项索引
     */
    async function remove(...indexes: number[]) {
        // 调用 Playlist.remove 方法删除指定 Midi 项
        Playlist.remove(playlist.value, ...indexes);

        // 如果当前播放列表的焦点索引为 -1
        if (getFocus() === -1) {
            // 关闭当前播放器
            await Playlist.Player.close(playlist.value);
        }

        // 进行保存
        await save("focus", "indexes", "items");
    }

    /**
     * 删除所有 Midi 项
     */
    async function removeAll() {
        // 调用 Playlist.removeAll 方法删除所有 Midi 项
        Playlist.removeAll(playlist.value);

        // 关闭当前播放器
        await Playlist.Player.close(playlist.value);

        // 进行保存
        await save("focus", "indexes", "items");
    }

    /**
     * 将指定索引的 Midi 项移动到指定位置
     * @param index1 要移动的 Midi 项索引
     * @param index2 要移动到的位置索引
     */
    async function swap(index1: number, index2: number) {
        // 调用 Playlist.swap 方法将指定 Midi 项移动到指定位置
        if (!Playlist.swap(playlist.value, index1, index2)) {
            return;
        }

        // 进行保存
        if (playlist.value.shuffle) {
            await save("focus", "indexes");
        } else {
            await save("focus", "items");
        }
    }

    /**
     * 切换播放模式
     */
    async function toggleShuffle() {
        Playlist.toggleShuffle(playlist.value);
        await save("focus", "indexes", "shuffle");
    }

    /**
     * 向下移动 Midi 项
     * @param index Midi 项索引
     */
    async function moveDown(index: number) {
        await swap(index, index + 1);
    }

    /**
     * 向上移动 Midi 项
     * @param index Midi 项索引
     */
    async function moveUp(index: number) {
        await swap(index - 1, index);
    }

    /**
     * 播放上一首
     */
    async function previous() {
        // 获取当前播放列表的长度
        const length = playlist.value.items.length;

        // 如果播放列表为空，则将焦点设置为 -1
        if (length === 0) {
            await setFocus(-1);
            return;
        }

        // 关闭当前播放器
        await Playlist.Player.close(playlist.value);

        // 如果焦点大于 0，则将焦点减 1；否则将焦点设置为列表长度减 1
        if (getFocus() > 0) {
            await setFocus(getFocus() - 1);
        } else {
            await setFocus(length - 1);
        }

        // 播放当前项
        await Playlist.Player.play(playlist.value);
    }

    /**
     * 播放下一首
     */
    async function next() {
        // 获取当前播放列表的长度
        const length = playlist.value.items.length;

        // 如果播放列表为空，则将焦点设置为 -1
        if (length === 0) {
            await setFocus(-1);
            return;
        }

        // 关闭当前播放器
        await Playlist.Player.close(playlist.value);

        // 如果焦点小于列表长度减 1，则将焦点加 1；否则将焦点设置为 0
        if (getFocus() < length - 1) {
            await setFocus(getFocus() + 1);
        } else {
            await setFocus(0);
        }

        // 播放当前项
        await Playlist.Player.play(playlist.value);
    }

    /**
     * 切换播放状态
     */
    async function togglePause() {
        // 没有打开项
        if (playlist.value.player.id === "") {
            if (playlist.value.items.length > 0) {
                if (getFocus() === -1) {
                    await setFocus(0);
                }
                await Playlist.Player.play(playlist.value);
            }
            return;
        }

        // 有打开项
        if (playlist.value.player.state === PlayState.Play) {
            await Playlist.Player.pause(playlist.value);
        } else {
            await Playlist.Player.play(playlist.value);
        }
    }

    return {
        playlist,
        length: computed(() => playlist.value.items.length),
        indexes: computed(() => playlist.value.indexes),
        items: computed(() => playlist.value.items),
        shuffle: computed(() => playlist.value.shuffle),
        player: computed(() => playlist.value.player),
        duration: computed(() => duration.value),
        load,
        save,
        getFocus,
        setFocus,
        getMode,
        setMode,
        insert,
        remove,
        removeAll,
        swap,
        toggleShuffle,
        moveDown,
        moveUp,
        previous,
        next,
        togglePause,
    };
});

if (import.meta.hot) {
    import.meta.hot.accept(acceptHMRUpdate(usePlaylistStore, import.meta.hot));
}

export default usePlaylistStore;
